.. _глава_45_start:

NULL значение и оператор is
============================

.. index::
    NULL
    is

В предыдущих главах мы видели, что переменная ссылочного типа не обязательно должна ссылаться на
на конкретный объект:

.. code-block:: d

    MyClass referencesAnObject = new MyClass;
    MyClass variable; // нет актуальной ссылки на объект

Будучи ссылочным типом, переменная выше имеет идентификатор, но она еще не
ссылается на какой-либо объект. Можно представить, что такой объект имеет место в
памяти, как показано на следующем рисунке:

.. image:: images/45_1.png

Ссылка, которая не ссылается ни на одно значение, есть null. Мы расскажем об этом подробнее ниже.
Такая переменная находится в почти бесполезном состоянии. Поскольку не существует объекта MyClass
на который она ссылается, ее нельзя использовать в контексте, где нужен реальный объект MyClass
необходим:

.. code-block:: d

    import std.stdio;

    class MyClass
    {
        int member;
    }

    void use(MyClass variable)
    {
        writeln(variable.member); // ← BUG
    }

    void main()
    {
        MyClass variable;
        use(variable);

    }

Поскольку не существует объекта, на который ссылается параметр, полученный функцией use(),
попытка получить доступ к члену несуществующего объекта приводит к аварийному завершению программы
краху:

.. code-block:: console

    $ ./deneme
    Segmentation fault


.. index::
    null

Значение null
-------------

Специальное значение null может быть напечатано так же, как и любое другое значение.

.. code-block:: d

    writeln(null);

Вывод

.. code-block:: console

     null

null переменная может использоваться только в двух контекстах:

* Присвоение объекта

.. code-block:: d

   variable = new MyClass; // теперь ссылается на объект

Приведенное выше присваивание заставляет переменную предоставлять доступ к новому
построенному объекту. С этого момента переменная может быть использована для любой допустимой
операции типа MyClass.

* Определение того, является ли она null

Однако, поскольку оператору == для сравнения нужны реальные объекты, приведенное ниже выражение
выражение ниже не может быть скомпилировано:

.. code-block:: d

    if (variable == null) // ← ошибка компиляции

По этой причине определение того, является ли переменная нулевой, должно осуществляться с помощью оператора is.

Оператор is
------------

Этот оператор отвечает на вопрос "имеет ли значение null?":

.. code-block:: d

    if (variable is null)
    {
    // Does not reference any object
    }

is можно использовать и с другими типами переменных. В следующем примере она
сравнивает значения двух целых чисел:

.. code-block:: d

    if (speed is newSpeed)
    {
        // Their values are equal
    }
    else
    {
        // Their values are different
    }

При использовании с фрагментами определяет, ссылаются ли два фрагмента на один и тот же
набор элементов:

.. code-block:: d

    if (slice is slice2)
    {
    // They provide access to the same elements
    }

Оператор !is
------------

Оператор !is является противоположным оператору is. Он выдает true, когда значения различны:

.. code-block:: d

    if (speed !is newSpeed)
    {
    // Their values are different
    }

Присвоение null значения
----------------------------

Присвоение переменной ссылочного типа значения null приводит к тому, что переменная
перестает ссылаться на свой текущий объект.
Если это присваивание завершает самую последнюю ссылку на
реальный объект, то этот объект становится кандидатом на удаление  сборщиком мусора.
сборщиком мусора. В конце концов, отсутствие ссылок на переменную означает, что объект
объект вообще не используется в программе.
Давайте рассмотрим пример из предыдущей главы (:ref:`Типы значения и ссылочные типы<глава_34_start>`), где две переменные
ссылались на один и тот же объект:

.. code-block:: d

    auto variable = new MyClass;
    auto variable2 = variable;

Ниже представлено состояние памяти после выполнения этого
кода:

.. image:: images/45.4_1.png

Присвоение нулевого значения одной из этих переменных нарушает ее связь с
объектом:

.. code-block:: d

        variable = null;

На данный момент есть только переменная variable2, которая ссылается на объект MyClass:

.. image:: images/45.4_2.png


Присвоение null последней ссылке сделает объект MyClass недоступным:

.. code-block:: d

        variable2 = null;

Такие недостижимые объекты завершаются сборщиком мусора через неопределенное время в
будущем. С точки зрения программы объект не существует:

.. image:: images/45.4_3.png


Мы уже обсуждали способы опустошения ассоциативного массива в разделе упражнений
главы "Ассоциативные массивы" (:ref:`Ассоциативные массивы<Ассоциативные массивы>`). Теперь мы знаем четвертый способ:
Присвоение null переменной ассоциативного массива нарушает связь этой
переменной с элементами:

.. code-block:: d

    string[int] names;
    // ...
    names = null; // Not providing access to any element

Итоги
------

* null - это значение, указывающее на то, что переменная не предоставляет доступа к какому-либо значению
  значению
* Ссылки, имеющие значение null, могут быть использованы только в двух операциях:
  присвоение им значения и определение того, являются ли они нулевыми или нет
* Поскольку оператор == может обращаться к реальному объекту, определение того, является ли переменная нулевой, должно выполняться в операторе is.
  является ли переменная нулевой, должен выполнять оператор is
* !is является противоположностью оператора is
* Присвоение переменной значения null приводит к тому, что эта переменная не имеет доступа ни к чему
* Объекты, на которые не ссылается ни одна переменная, завершаются сборщиком мусора
